home *** CD-ROM | disk | FTP | other *** search
/ PC Advisor 2011 May / PC Advisor 190 E.iso / pc / ESSENTIALS / VLC Media Player 1.1 / vlc-1.1.5-win32.exe / sdk / include / vlc / plugins / vlc_arrays.h < prev    next >
Encoding:
C/C++ Source or Header  |  2010-11-13  |  22.7 KB  |  621 lines

  1. /*****************************************************************************
  2.  * vlc_arrays.h : Arrays and data structures handling
  3.  *****************************************************************************
  4.  * Copyright (C) 1999-2004 the VideoLAN team
  5.  * $Id: 390c1b6d9df4d275619b9c62945d352e063b4229 $
  6.  *
  7.  * Authors: Samuel Hocevar <sam@zoy.org>
  8.  *          Cl├⌐ment Stenac <zorglub@videolan.org>
  9.  *
  10.  * This program is free software; you can redistribute it and/or modify
  11.  * it under the terms of the GNU General Public License as published by
  12.  * the Free Software Foundation; either version 2 of the License, or
  13.  * (at your option) any later version.
  14.  *
  15.  * This program is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  * GNU General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU General Public License
  21.  * along with this program; if not, write to the Free Software
  22.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  23.  *****************************************************************************/
  24.  
  25. #ifndef VLC_ARRAYS_H_
  26. #define VLC_ARRAYS_H_
  27.  
  28. /**
  29.  * \file
  30.  * This file defines functions, structures and macros for handling arrays in vlc
  31.  */
  32.  
  33. /* realloc() that never fails *if* downsizing */
  34. static inline void *realloc_down( void *ptr, size_t size )
  35. {
  36.     void *ret = realloc( ptr, size );
  37.     return ret ? ret : ptr;
  38. }
  39.  
  40. /**
  41.  * Simple dynamic array handling. Array is realloced at each insert/removal
  42.  */
  43. #if defined( _MSC_VER ) && _MSC_VER < 1300 && !defined( UNDER_CE )
  44. #   define VLCCVP (void**) /* Work-around for broken compiler */
  45. #else
  46. #   define VLCCVP
  47. #endif
  48. #define INSERT_ELEM( p_ar, i_oldsize, i_pos, elem )                           \
  49.     do                                                                        \
  50.     {                                                                         \
  51.         if( !i_oldsize ) (p_ar) = NULL;                                       \
  52.         (p_ar) = VLCCVP realloc( p_ar, ((i_oldsize) + 1) * sizeof(*(p_ar)) ); \
  53.         if( !(p_ar) ) abort();                                                \
  54.         if( (i_oldsize) - (i_pos) )                                           \
  55.         {                                                                     \
  56.             memmove( (p_ar) + (i_pos) + 1, (p_ar) + (i_pos),                  \
  57.                      ((i_oldsize) - (i_pos)) * sizeof( *(p_ar) ) );           \
  58.         }                                                                     \
  59.         (p_ar)[i_pos] = elem;                                                 \
  60.         (i_oldsize)++;                                                        \
  61.     }                                                                         \
  62.     while( 0 )
  63.  
  64. #define REMOVE_ELEM( p_ar, i_size, i_pos )                                    \
  65.     do                                                                        \
  66.     {                                                                         \
  67.         if( (i_size) - (i_pos) - 1 )                                          \
  68.         {                                                                     \
  69.             memmove( (p_ar) + (i_pos),                                        \
  70.                      (p_ar) + (i_pos) + 1,                                    \
  71.                      ((i_size) - (i_pos) - 1) * sizeof( *(p_ar) ) );          \
  72.         }                                                                     \
  73.         if( i_size > 1 )                                                      \
  74.             (p_ar) = realloc_down( p_ar, ((i_size) - 1) * sizeof( *(p_ar) ) );\
  75.         else                                                                  \
  76.         {                                                                     \
  77.             free( p_ar );                                                     \
  78.             (p_ar) = NULL;                                                    \
  79.         }                                                                     \
  80.         (i_size)--;                                                           \
  81.     }                                                                         \
  82.     while( 0 )
  83.  
  84. #define TAB_INIT( count, tab )                  \
  85.   do {                                          \
  86.     (count) = 0;                                \
  87.     (tab) = NULL;                               \
  88.   } while(0)
  89.  
  90. #define TAB_CLEAN( count, tab )                 \
  91.   do {                                          \
  92.     free( tab );                                \
  93.     (count)= 0;                                 \
  94.     (tab)= NULL;                                \
  95.   } while(0)
  96.  
  97. #define TAB_APPEND_CAST( cast, count, tab, p )             \
  98.   do {                                          \
  99.     if( (count) > 0 )                           \
  100.         (tab) = cast realloc( tab, sizeof( void ** ) * ( (count) + 1 ) ); \
  101.     else                                        \
  102.         (tab) = cast malloc( sizeof( void ** ) );    \
  103.     if( !(tab) ) abort();                       \
  104.     (tab)[count] = (p);                         \
  105.     (count)++;                                  \
  106.   } while(0)
  107.  
  108. #define TAB_APPEND( count, tab, p )             \
  109.     TAB_APPEND_CAST( , count, tab, p )
  110. #define TAB_APPEND_CPP( type, count, tab, p )   \
  111.     TAB_APPEND_CAST( (type**), count, tab, p )
  112.  
  113. #define TAB_FIND( count, tab, p, index )        \
  114.   do {                                          \
  115.         int _i_;                                \
  116.         (index) = -1;                           \
  117.         for( _i_ = 0; _i_ < (count); _i_++ )    \
  118.         {                                       \
  119.             if( (tab)[_i_] == (p) )             \
  120.             {                                   \
  121.                 (index) = _i_;                  \
  122.                 break;                          \
  123.             }                                   \
  124.         }                                       \
  125.   } while(0)
  126.  
  127.  
  128. #define TAB_REMOVE( count, tab, p )             \
  129.   do {                                          \
  130.         int _i_index_;                          \
  131.         TAB_FIND( count, tab, p, _i_index_ );   \
  132.         if( _i_index_ >= 0 )                    \
  133.         {                                       \
  134.             if( (count) > 1 )                   \
  135.             {                                   \
  136.                 memmove( ((void**)(tab) + _i_index_),    \
  137.                          ((void**)(tab) + _i_index_+1),  \
  138.                          ( (count) - _i_index_ - 1 ) * sizeof( void* ) );\
  139.             }                                   \
  140.             (count)--;                          \
  141.             if( (count) == 0 )                  \
  142.             {                                   \
  143.                 free( tab );                    \
  144.                 (tab) = NULL;                   \
  145.             }                                   \
  146.         }                                       \
  147.   } while(0)
  148.  
  149. #define TAB_INSERT_CAST( cast, count, tab, p, index ) do { \
  150.     if( (count) > 0 )                           \
  151.         (tab) = cast realloc( tab, sizeof( void ** ) * ( (count) + 1 ) ); \
  152.     else                                        \
  153.         (tab) = cast malloc( sizeof( void ** ) );       \
  154.     if( !(tab) ) abort();                       \
  155.     if( (count) - (index) > 0 )                 \
  156.         memmove( (void**)(tab) + (index) + 1,   \
  157.                  (void**)(tab) + (index),       \
  158.                  ((count) - (index)) * sizeof(*(tab)) );\
  159.     (tab)[(index)] = (p);                       \
  160.     (count)++;                                  \
  161. } while(0)
  162.  
  163. #define TAB_INSERT( count, tab, p, index )      \
  164.     TAB_INSERT_CAST( , count, tab, p, index )
  165.  
  166. /**
  167.  * Binary search in a sorted array. The key must be comparable by < and >
  168.  * \param entries array of entries
  169.  * \param count number of entries
  170.  * \param elem key to check within an entry (like .id, or ->i_id)
  171.  * \param zetype type of the key
  172.  * \param key value of the key
  173.  * \param answer index of answer within the array. -1 if not found
  174.  */
  175. #define BSEARCH( entries, count, elem, zetype, key, answer ) \
  176.    do {  \
  177.     int low = 0, high = count - 1;   \
  178.     answer = -1; \
  179.     while( low <= high ) {\
  180.         int mid = (low + high ) / 2; /* Just don't care about 2^30 tables */ \
  181.         zetype mid_val = entries[mid] elem;\
  182.         if( mid_val < key ) \
  183.             low = mid + 1; \
  184.         else if ( mid_val > key ) \
  185.             high = mid -1;  \
  186.         else    \
  187.         {   \
  188.             answer = mid;  break;   \
  189.         }\
  190.     } \
  191.  } while(0)
  192.  
  193.  
  194. /************************************************************************
  195.  * Dynamic arrays with progressive allocation
  196.  ************************************************************************/
  197.  
  198. /* Internal functions */
  199. #define _ARRAY_ALLOC(array, newsize) {                                      \
  200.     (array).i_alloc = newsize;                                              \
  201.     (array).p_elems = VLCCVP realloc( (array).p_elems, (array).i_alloc *    \
  202.                                     sizeof(*(array).p_elems) );             \
  203.     if( !(array).p_elems ) abort();                                         \
  204. }
  205.  
  206. #define _ARRAY_GROW1(array) {                                               \
  207.     if( (array).i_alloc < 10 )                                              \
  208.         _ARRAY_ALLOC(array, 10 )                                            \
  209.     else if( (array).i_alloc == (array).i_size )                            \
  210.         _ARRAY_ALLOC(array, (int)(array.i_alloc * 1.5) )                    \
  211. }
  212.  
  213. #define _ARRAY_GROW(array,additional) {                                     \
  214.      int i_first = (array).i_alloc;                                         \
  215.      while( (array).i_alloc - i_first < additional )                        \
  216.      {                                                                      \
  217.          if( (array).i_alloc < 10 )                                         \
  218.             _ARRAY_ALLOC(array, 10 )                                        \
  219.         else if( (array).i_alloc == (array).i_size )                        \
  220.             _ARRAY_ALLOC(array, (int)((array).i_alloc * 1.5) )              \
  221.         else break;                                                         \
  222.      }                                                                      \
  223. }
  224.  
  225. #define _ARRAY_SHRINK(array) {                                              \
  226.     if( (array).i_size > 10 && (array).i_size < (int)((array).i_alloc / 1.5) ) {  \
  227.         _ARRAY_ALLOC(array, (array).i_size + 5);                            \
  228.     }                                                                       \
  229. }
  230.  
  231. #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
  232.  
  233. /* API */
  234. #define DECL_ARRAY(type) struct {                                           \
  235.     int i_alloc;                                                            \
  236.     int i_size;                                                             \
  237.     type *p_elems;                                                          \
  238. }
  239.  
  240. #define TYPEDEF_ARRAY(type, name) typedef DECL_ARRAY(type) name;
  241.  
  242. #define ARRAY_INIT(array)                                                   \
  243.   do {                                                                      \
  244.     (array).i_alloc = 0;                                                    \
  245.     (array).i_size = 0;                                                     \
  246.     (array).p_elems = NULL;                                                 \
  247.   } while(0)
  248.  
  249. #define ARRAY_RESET(array)                                                  \
  250.   do {                                                                      \
  251.     (array).i_alloc = 0;                                                    \
  252.     (array).i_size = 0;                                                     \
  253.     free( (array).p_elems ); (array).p_elems = NULL;                        \
  254.   } while(0)
  255.  
  256. #define ARRAY_APPEND(array, elem)                                           \
  257.   do {                                                                      \
  258.     _ARRAY_GROW1(array);                                                    \
  259.     (array).p_elems[(array).i_size] = elem;                                 \
  260.     (array).i_size++;                                                       \
  261.   } while(0)
  262.  
  263. #define ARRAY_INSERT(array,elem,pos)                                        \
  264.   do {                                                                      \
  265.     _ARRAY_GROW1(array);                                                    \
  266.     if( (array).i_size - pos ) {                                            \
  267.         memmove( (array).p_elems + pos + 1, (array).p_elems + pos,          \
  268.                  ((array).i_size-pos) * sizeof(*(array).p_elems) );         \
  269.     }                                                                       \
  270.     (array).p_elems[pos] = elem;                                            \
  271.     (array).i_size++;                                                       \
  272.   } while(0)
  273.  
  274. #define ARRAY_REMOVE(array,pos)                                             \
  275.   do {                                                                      \
  276.     if( (array).i_size - (pos) - 1 )                                        \
  277.     {                                                                       \
  278.         memmove( (array).p_elems + pos, (array).p_elems + pos + 1,          \
  279.                  ( (array).i_size - pos - 1 ) *sizeof(*(array).p_elems) );  \
  280.     }                                                                       \
  281.     (array).i_size--;                                                       \
  282.     _ARRAY_SHRINK(array);                                                   \
  283.   } while(0)
  284.  
  285. #define ARRAY_VAL(array, pos) array.p_elems[pos]
  286.  
  287. #define ARRAY_BSEARCH(array, elem, zetype, key, answer) \
  288.     BSEARCH( (array).p_elems, (array).i_size, elem, zetype, key, answer)
  289.  
  290. #define FOREACH_ARRAY( item, array ) { \
  291.     int fe_idx; \
  292.     for( fe_idx = 0 ; fe_idx < (array).i_size ; fe_idx++ ) \
  293.     { \
  294.         item = (array).p_elems[fe_idx];
  295.  
  296. #define FOREACH_END() } }
  297.  
  298.  
  299. /************************************************************************
  300.  * Dynamic arrays with progressive allocation (Preferred API)
  301.  ************************************************************************/
  302. typedef struct vlc_array_t
  303. {
  304.     int i_count;
  305.     void ** pp_elems;
  306. } vlc_array_t;
  307.  
  308. static inline void vlc_array_init( vlc_array_t * p_array )
  309. {
  310.     memset( p_array, 0, sizeof(vlc_array_t) );
  311. }
  312.  
  313. static inline void vlc_array_clear( vlc_array_t * p_array )
  314. {
  315.     free( p_array->pp_elems );
  316.     memset( p_array, 0, sizeof(vlc_array_t) );
  317. }
  318.  
  319. static inline vlc_array_t * vlc_array_new( void )
  320. {
  321.     vlc_array_t * ret = (vlc_array_t *)malloc( sizeof(vlc_array_t) );
  322.     if( ret ) vlc_array_init( ret );
  323.     return ret;
  324. }
  325.  
  326. static inline void vlc_array_destroy( vlc_array_t * p_array )
  327. {
  328.     if( !p_array )
  329.         return;
  330.     vlc_array_clear( p_array );
  331.     free( p_array );
  332. }
  333.  
  334.  
  335. /* Read */
  336. static inline int
  337. vlc_array_count( vlc_array_t * p_array )
  338. {
  339.     return p_array->i_count;
  340. }
  341.  
  342. static inline void *
  343. vlc_array_item_at_index( vlc_array_t * p_array, int i_index )
  344. {
  345.     return p_array->pp_elems[i_index];
  346. }
  347.  
  348. static inline int
  349. vlc_array_index_of_item( vlc_array_t * p_array, void * item )
  350. {
  351.     int i;
  352.     for( i = 0; i < p_array->i_count; i++)
  353.     {
  354.         if( p_array->pp_elems[i] == item )
  355.             return i;
  356.     }
  357.     return -1;
  358. }
  359.  
  360. /* Write */
  361. static inline void
  362. vlc_array_insert( vlc_array_t * p_array, void * p_elem, int i_index )
  363. {
  364.     TAB_INSERT_CAST( (void **), p_array->i_count, p_array->pp_elems, p_elem, i_index );
  365. }
  366.  
  367. static inline void
  368. vlc_array_append( vlc_array_t * p_array, void * p_elem )
  369. {
  370.     vlc_array_insert( p_array, p_elem, p_array->i_count );
  371. }
  372.  
  373. static inline void
  374. vlc_array_remove( vlc_array_t * p_array, int i_index )
  375. {
  376.     if( i_index >= 0 )
  377.     {
  378.         if( p_array->i_count > 1 )
  379.         {
  380.             memmove( p_array->pp_elems + i_index,
  381.                      p_array->pp_elems + i_index+1,
  382.                      ( p_array->i_count - i_index - 1 ) * sizeof( void* ) );
  383.         }
  384.         p_array->i_count--;
  385.         if( p_array->i_count == 0 )
  386.         {
  387.             free( p_array->pp_elems );
  388.             p_array->pp_elems = NULL;
  389.         }
  390.     }
  391. }
  392.  
  393.  
  394. /************************************************************************
  395.  * Dictionaries
  396.  ************************************************************************/
  397.  
  398. /* This function is not intended to be crypto-secure, we only want it to be
  399.  * fast and not suck too much. This one is pretty fast and did 0 collisions
  400.  * in wenglish's dictionary.
  401.  */
  402. static inline uint64_t DictHash( const char *psz_string, int hashsize )
  403. {
  404.     uint64_t i_hash = 0;
  405.     if( psz_string )
  406.     {
  407.         while( *psz_string )
  408.         {
  409.             i_hash += *psz_string++;
  410.             i_hash += i_hash << 10;
  411.             i_hash ^= i_hash >> 8;
  412.         }
  413.     }
  414.     return i_hash % hashsize;
  415. }
  416.  
  417. typedef struct vlc_dictionary_entry_t
  418. {
  419.     char *   psz_key;
  420.     void *   p_value;
  421.     struct vlc_dictionary_entry_t * p_next;
  422. } vlc_dictionary_entry_t;
  423.  
  424. typedef struct vlc_dictionary_t
  425. {
  426.     int i_size;
  427.     vlc_dictionary_entry_t ** p_entries;
  428. } vlc_dictionary_t;
  429.  
  430. static void * const kVLCDictionaryNotFound = NULL;
  431.  
  432. static inline void vlc_dictionary_init( vlc_dictionary_t * p_dict, int i_size )
  433. {
  434.     p_dict->p_entries = NULL;
  435.  
  436.     if( i_size > 0 )
  437.     {
  438.         p_dict->p_entries = (vlc_dictionary_entry_t **)calloc( i_size, sizeof(*p_dict->p_entries) );
  439.         if( !p_dict->p_entries )
  440.             i_size = 0;
  441.     }
  442.     p_dict->i_size = i_size;
  443. }
  444.  
  445. static inline void vlc_dictionary_clear( vlc_dictionary_t * p_dict,
  446.                                          void ( * pf_free )( void * p_data, void * p_obj ),
  447.                                          void * p_obj )
  448. {
  449.     if( p_dict->p_entries )
  450.     {
  451.         for( int i = 0; i < p_dict->i_size; i++ )
  452.         {
  453.             vlc_dictionary_entry_t * p_current, * p_next;
  454.             p_current = p_dict->p_entries[i];
  455.             while( p_current )
  456.             {
  457.                 p_next = p_current->p_next;
  458.                 if( pf_free != NULL )
  459.                     ( * pf_free )( p_current->p_value, p_obj );
  460.                 free( p_current->psz_key );
  461.                 free( p_current );
  462.                 p_current = p_next;
  463.             }
  464.         }
  465.         free( p_dict->p_entries );
  466.         p_dict->p_entries = NULL;
  467.     }
  468.     p_dict->i_size = 0;
  469. }
  470.  
  471.  
  472.  
  473. static inline void *
  474. vlc_dictionary_value_for_key( const vlc_dictionary_t * p_dict, const char * psz_key )
  475. {
  476.     if( !p_dict->p_entries )
  477.         return kVLCDictionaryNotFound;
  478.  
  479.     int i_pos = DictHash( psz_key, p_dict->i_size );
  480.     vlc_dictionary_entry_t * p_entry = p_dict->p_entries[i_pos];
  481.  
  482.     if( !p_entry )
  483.         return kVLCDictionaryNotFound;
  484.  
  485.     /* Make sure we return the right item. (Hash collision) */
  486.     do {
  487.         if( !strcmp( psz_key, p_entry->psz_key ) )
  488.             return p_entry->p_value;
  489.         p_entry = p_entry->p_next;
  490.     } while( p_entry );
  491.  
  492.     return kVLCDictionaryNotFound;
  493. }
  494.  
  495. static inline int
  496. vlc_dictionary_keys_count( const vlc_dictionary_t * p_dict )
  497. {
  498.     vlc_dictionary_entry_t * p_entry;
  499.     int i, count = 0;
  500.  
  501.     if( !p_dict->p_entries )
  502.         return 0;
  503.  
  504.     for( i = 0; i < p_dict->i_size; i++ )
  505.     {
  506.         for( p_entry = p_dict->p_entries[i]; p_entry; p_entry = p_entry->p_next ) count++;
  507.     }
  508.     return count;
  509. }
  510.  
  511. static inline char **
  512. vlc_dictionary_all_keys( const vlc_dictionary_t * p_dict )
  513. {
  514.     vlc_dictionary_entry_t * p_entry;
  515.     char ** ppsz_ret;
  516.     int i, count = vlc_dictionary_keys_count( p_dict );
  517.  
  518.     ppsz_ret = (char**)malloc(sizeof(char *) * (count + 1));
  519.  
  520.     count = 0;
  521.     for( i = 0; i < p_dict->i_size; i++ )
  522.     {
  523.         for( p_entry = p_dict->p_entries[i]; p_entry; p_entry = p_entry->p_next )
  524.             ppsz_ret[count++] = strdup( p_entry->psz_key );
  525.     }
  526.     ppsz_ret[count] = NULL;
  527.     return ppsz_ret;
  528. }
  529.  
  530. static inline void
  531. __vlc_dictionary_insert( vlc_dictionary_t * p_dict, const char * psz_key,
  532.                          void * p_value, bool rebuild )
  533. {
  534.     if( !p_dict->p_entries )
  535.         vlc_dictionary_init( p_dict, 1 );
  536.  
  537.     int i_pos = DictHash( psz_key, p_dict->i_size );
  538.     vlc_dictionary_entry_t * p_entry;
  539.  
  540.     p_entry = (vlc_dictionary_entry_t *)malloc(sizeof(*p_entry));
  541.     p_entry->psz_key = strdup( psz_key );
  542.     p_entry->p_value = p_value;
  543.     p_entry->p_next = p_dict->p_entries[i_pos];
  544.     p_dict->p_entries[i_pos] = p_entry;
  545.     if( rebuild )
  546.     {
  547.         /* Count how many items there was */
  548.         int count;
  549.         for( count = 1; p_entry->p_next; count++ )
  550.             p_entry = p_entry->p_next;
  551.         if( count > 3 ) /* XXX: this need tuning */
  552.         {
  553.             /* Here it starts to be not good, rebuild a bigger dictionary */
  554.             struct vlc_dictionary_t new_dict;
  555.             int i_new_size = ( (p_dict->i_size+2) * 3) / 2; /* XXX: this need tuning */
  556.             int i;
  557.             vlc_dictionary_init( &new_dict, i_new_size );
  558.             for( i = 0; i < p_dict->i_size; i++ )
  559.             {
  560.                 p_entry = p_dict->p_entries[i];
  561.                 while( p_entry )
  562.                 {
  563.                     __vlc_dictionary_insert( &new_dict, p_entry->psz_key,
  564.                                              p_entry->p_value,
  565.                                              false /* To avoid multiple rebuild loop */);
  566.                     p_entry = p_entry->p_next;
  567.                 }
  568.             }
  569.  
  570.             vlc_dictionary_clear( p_dict, NULL, NULL );
  571.             p_dict->i_size = new_dict.i_size;
  572.             p_dict->p_entries = new_dict.p_entries;
  573.         }
  574.     }
  575. }
  576.  
  577. static inline void
  578. vlc_dictionary_insert( vlc_dictionary_t * p_dict, const char * psz_key, void * p_value )
  579. {
  580.     __vlc_dictionary_insert( p_dict, psz_key, p_value, true );
  581. }
  582.  
  583. static inline void
  584. vlc_dictionary_remove_value_for_key( const vlc_dictionary_t * p_dict, const char * psz_key,
  585.                                      void ( * pf_free )( void * p_data, void * p_obj ),
  586.                                      void * p_obj )
  587. {
  588.     if( !p_dict->p_entries )
  589.         return;
  590.  
  591.     int i_pos = DictHash( psz_key, p_dict->i_size );
  592.     vlc_dictionary_entry_t * p_entry = p_dict->p_entries[i_pos];
  593.     vlc_dictionary_entry_t * p_prev;
  594.  
  595.     if( !p_entry )
  596.         return; /* Not found, nothing to do */
  597.  
  598.     /* Hash collision */
  599.     p_prev = NULL;
  600.     do {
  601.         if( !strcmp( psz_key, p_entry->psz_key ) )
  602.         {
  603.             if( pf_free != NULL )
  604.                 ( * pf_free )( p_entry->p_value, p_obj );
  605.             if( !p_prev )
  606.                 p_dict->p_entries[i_pos] = p_entry->p_next;
  607.             else
  608.                 p_prev->p_next = p_entry->p_next;
  609.             free( p_entry->psz_key );
  610.             free( p_entry );
  611.             return;
  612.         }
  613.         p_prev = p_entry;
  614.         p_entry = p_entry->p_next;
  615.     } while( p_entry );
  616.  
  617.     /* No key was found */
  618. }
  619.  
  620. #endif
  621.